package c_Controler;


public class Tabuleiro {
	private int tamanho;
	private int numeroBombas;
	private Casa[][] casas;
	
	public Tabuleiro(int tamanho) {
		if(tamanho < 1 || tamanho > 99) throw new Error("Tamanho invalido");
		this.tamanho = tamanho;
		this.casas = new Casa[this.tamanho][this.tamanho];
		for (int i = 0; i < casas.length; i++) {
			for (int j = 0; j < casas.length; j++) {
				casas[i][j] = new Casa(false);
			}
		}
		this.numeroBombas = this.calculaNumeroBombas(tamanho);
		this.geraTabuleiro();
	}

	//Cria o tabuleiro configurado.
	private void geraTabuleiro() {
		this.addBombas();
	}
	
	//Calcula o numero de bombas impares do tabuleiro
	private int calculaNumeroBombas(int numero) {
		if(numero < 2) throw new Error("Tamanho invalido");
		else return (numero-1) + (numero-2);
	}
	
	//Add as bombas randomicamente ao tabuleiro.
	private void addBombas() {
		double[] posicoesBombas = this.getPosicoesBombas();
		int linha, coluna;
		for (int i = 0; i < posicoesBombas.length; i++) {
			linha = (int)posicoesBombas[i];
			if(tamanho < 10) coluna = (int)(posicoesBombas[i]*10)%10;
			else coluna = (int)(posicoesBombas[i]*100)%100;
			casas[linha][coluna].setBomba(true);
			calculaAdjacencias(linha, coluna);
		}
	}
	
	private void calculaAdjacencias(int linha, int coluna) {
		for (int i = linha-1; i < linha+2; i++) {
			if((i >= 0) && (i < tamanho) && (coluna-1) >= 0) { //garantir que nao acesse posicoes invalidas do array
				int pos0 = casas[i][coluna-1].getNumeroAdjacencias();
				pos0++;
				casas[i][coluna-1].setNumeroAdjacencias(pos0);
			}
			if((i >= 0) && (i < tamanho)) {
				int pos1 = casas[i][coluna].getNumeroAdjacencias();
				pos1++;
				casas[i][coluna].setNumeroAdjacencias(pos1);
			}
			if((i >= 0) && (i < tamanho) && (coluna+1) < tamanho) {
				int pos2 = casas[i][coluna+1].getNumeroAdjacencias();
				pos2++;
				casas[i][coluna+1].setNumeroAdjacencias(pos2);
			}
		}
	}

	//Retorna um array de double representando o valor da linha e coluna da bomba como um double l,c
	private double[] getPosicoesBombas() {
		double[] posicoes = new double[numeroBombas];
		double add;
		for (int i = 0; i < posicoes.length; i++) { //incializando os valores do array para a condicao statusOk funfah
			posicoes[i] = -1.0;
		}
		int j = 0;

		do {
			add = calculaPosicaoBomba();
			if(!contem(posicoes, add)) {
				posicoes[j] = add;
				j++;
			}	
		} while (!statusOK(posicoes));
		return posicoes;
	}
	
	//METODO AUX que verifica se o array de posicoes estah completamente preenchido
	private boolean statusOK(double[] pos) {
		for (int i = 0; i < pos.length; i++) {
			if(pos[i] == -1.0) return false;
		}
		return true;
	}

	//METODO AUX que verifica se ja contem um valor sorteado dentro do array de posicoes
	private boolean contem(double[] pos, double num) {
		for (int i = 0; i < pos.length; i++) {
			if(pos[i] == num) return true;
		}
		return false;
	}
	//Calcula uma posicao L,C baseado no tamanho do tabuleiro
	private double calculaPosicaoBomba() {
		double menorPosicao = 0.0;
		double maiorPosicao;
		int maiorPosicaoColuna;
		int intervaloDecimal; //oscila entre a menor posicao de linha e a maior de coluna;
		double valorRandomico = random(tamanho);
		if(tamanho < 10) {
			maiorPosicao = ((tamanho-1) + (tamanho-1)*0.1);
			maiorPosicaoColuna =  (int)((maiorPosicao*10)%10);
			intervaloDecimal = (int)((valorRandomico*10)%10);
		} else {
			maiorPosicao = ((tamanho-1) + (tamanho-1)*0.01);
			maiorPosicaoColuna = (int)((maiorPosicao*100)%100);
			intervaloDecimal = (int)((valorRandomico*100)%100);
		}
		if((valorRandomico >= menorPosicao) && (valorRandomico <= maiorPosicao) && ((int)valorRandomico <= (int)maiorPosicao) && 
			(intervaloDecimal <= maiorPosicaoColuna) && (intervaloDecimal >= 0)) return valorRandomico;
		else return calculaPosicaoBomba();
	}
	
	//Escolhe o intervalo dos numeros randomicos baseado no tamanho do tabuleiro
	private double random(int tamanho) {
		if(tamanho < 10) return (double)(int)((Math.random())*100)/10; //0.0 a 10
		return (double)(int)((Math.random())*10000)/100; //00.00 a 100
	}
	
	public String toString() {
		String toString = "";
		for (int i = 0; i < tamanho; i++) {
			toString += "|";
			for (int j = 0; j < tamanho; j++) {
				toString += casas[i][j].toString();
				toString += "|";
			}
			toString += "\n";
		}
		return toString;
	}
	
	public String toString2() {
		String toString = "";
		for (int i = 0; i < tamanho; i++) {
			toString += "|";
			for (int j = 0; j < tamanho; j++) {
				casas[i][j].setIdentificada(true);
				toString += casas[i][j].toString();
				toString += "|";
			}
			toString += "\n";
		}
		for (int i = 0; i < tamanho; i++) {
			for (int j = 0; j < tamanho; j++) {
				casas[i][j].setIdentificada(false);
			}
			
		}
		return toString;
	}
	
	
	public void jogada(int linha, int coluna) {
		if((linha > tamanho) || (coluna > tamanho)) throw new Error("Entrada invalida");
		if(!casas[linha][coluna].getEhBomba())
			if(casas[linha][coluna].getNumeroAdjacencias() == 0)
				abreAdjacencias(linha, coluna);
		casas[linha][coluna].setIdentificada(true);
	}

	private void abreAdjacencias(int linha, int coluna) {
		if((linha >= 0) && (linha < tamanho) && (coluna >= 0) && (coluna < tamanho)) { //garante que ha acesso a posicoes fora de faixa
			if((casas[linha][coluna].getNumeroAdjacencias() != 0 && !casas[linha][coluna].getIdentificada())) { //identifica as casas com adjacencias nao identificadas
				casas[linha][coluna].setIdentificada(true);
			} else {
				if(!casas[linha][coluna].getIdentificada()) { //garante que a casa atual nao estah identificada, ou seja, estah para ser analisada.
					casas[linha][coluna].setIdentificada(true);
					if(linha-1 >= 0 && coluna-1 >= 0) abreAdjacencias(linha-1, coluna-1);
					if(linha-1 >= 0) abreAdjacencias(linha-1, coluna);
					if(linha-1 >= 0 && coluna+1 < tamanho) abreAdjacencias(linha-1, coluna+1);
					if(coluna-1 >= 0) abreAdjacencias(linha, coluna-1);
					if(coluna+1 < tamanho) abreAdjacencias(linha, coluna+1);
					if(linha+1 < tamanho && coluna-1 >= 0) abreAdjacencias(linha+1, coluna-1);
					if(linha+1 < tamanho) abreAdjacencias(linha+1, coluna);
					if(linha+1 < tamanho && coluna+1 < tamanho) abreAdjacencias(linha+1, coluna+1);
				} else return;
			}
		} else return;
	}
}
